package tool

import dao.ModeDao
import org.biojava.nbio.core.sequence.io.FastaReaderHelper
import org.joda.time.DateTime
import play.api.mvc._
import shared.VarTool
import utils.Utils

import java.io.File
import java.nio.file.Files
import scala.jdk.CollectionConverters._
import models.Tables._
import implicits.Implicits._
import play.api.libs.Files.TemporaryFile

import java.net.URLEncoder

/**
 * Created by yz on 17/9/2021
 */
object Tool extends MissionTool with ProjectTool {

  val dbName = "pathogen_database"
  val playPath = new File("../").getAbsolutePath
  val linuxPath = playPath + s"/${dbName}"
  val windowsPath = s"E:\\${dbName}"
  val path = {
    if (new File(windowsPath).exists()) windowsPath else linuxPath
  }
  val windowsTestDir = new File("C:\\temp")
  val linuxTestDir = new File(playPath, "workspace")
  val testDir = if (windowsTestDir.exists()) windowsTestDir else linuxTestDir
  val userDir = new File(path, "user")
  val binPath = new File(path, "bin")
  val exampleDir = new File(path, "example")
  val dataDir = new File(path, "data")
  val indexDir = new File(dataDir, "indexs")
  val blastFile = new File(Tool.path, "ncbi-blast-2.6.0+/bin/blastn")
  val makeBlastDbFile = new File(Tool.path, "ncbi-blast-2.6.0+/bin/makeblastdb")
  val blast2HtmlFile = new File(Tool.path, "blast2html-82b8c9722996/blast2html.py")
  val jinjaDir = new File(path, "jinjia")

  val scriptHtml =
    """
      |<script>
      |	$(function () {
      |			    $("footer:first").remove()
      |        $("#content").css("margin","0")
      |       $(".linkheader>a").each(function () {
      |				   var text=$(this).text()
      |				   $(this).replaceWith("<span style='color: #222222;'>"+text+"</span>")
      |			   })
      |
      |      $("tr").each(function () {
      |         var a=$(this).find("td>a:last")
      |					var text=a.text()
      |					a.replaceWith("<span style='color: #222222;'>"+text+"</span>")
      |				})
      |
      |       $("p.titleinfo>a").each(function () {
      |				   var text=$(this).text()
      |				   $(this).replaceWith("<span style='color: #606060;'>"+text+"</span>")
      |			   })
      |
      |       $(".param:eq(1)").parent().hide()
      |       $(".linkheader").hide()
      |
      |			})
      |</script>
    """.stripMargin

  val availCpu = Runtime.getRuntime.availableProcessors() - 1

  def getOutHtmlFile(dir: File) = {
    new File(dir, "out.html")
  }

  def getOutTableFile(dir: File) = {
    new File(dir, "data.xls")
  }

  def getSeqFile(dir: File) = {
    new File(dir, "seq.fa")
  }

  def getFq1File(dir: File) = {
    new File(dir, "1.fq")
  }

  def getViewFile(dir: File,missionName:String) = {
    new File(dir, s"${missionName}_view.txt")
  }

  def getDataDir(dir: File) = {
    new File(dir, "data")
  }

  def getFq2File(dir: File) = {
    new File(dir, "2.fq")
  }

  def getReportFile(dir: File) = {
    new File(dir, "report.txt")
  }

  def getOutputFile(dir: File) = {
    new File(dir, "output.txt")
  }

  def getUserIdPath(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Tool.userDir, userId.toString)
  }

  def getUserDataPath(implicit request: RequestHeader) = {
    val userIdFile = getUserIdPath
    new File(userIdFile, "data")
  }

  def getSampleFileById(sampleId: Int)(implicit request: RequestHeader) = {
    val userDataFile = getUserDataPath
    new File(userDataFile, s"${sampleId}.fa")
  }

  def getUserId(implicit request: RequestHeader) = {
    request.session.get(VarTool.idStr).get.toInt
  }

  def isFastaFile(file: File) = {
    val proteins = FastaReaderHelper.readFastaProteinSequence(file).asScala
    val dnas = FastaReaderHelper.readFastaDNASequence(file).asScala
    if (proteins.size == 0 && dnas.size == 0) {
      false
    } else true
  }

  def getFastaAttr(file: File) = {
    case class FastaAttr(kind: String, maxLength: Int, minLength: Int, size: Int, meanLength: Int)
    val proteins = FastaReaderHelper.readFastaProteinSequence(file).asScala
    val dnas = FastaReaderHelper.readFastaDNASequence(file).asScala
    if (dnas.size >= proteins.size) {
      val sortSeqNum = dnas.values.map(x => x.getSequenceAsString.size).toBuffer.sorted
      FastaAttr("核酸", sortSeqNum.last, sortSeqNum.head, sortSeqNum.size, sortSeqNum.sum / sortSeqNum.size)
    } else {
      val sortSeqNum = proteins.values.map(x => x.getSequenceAsString.size).toBuffer.sorted
      FastaAttr("蛋白", sortSeqNum.last, sortSeqNum.head, sortSeqNum.size, sortSeqNum.sum / sortSeqNum.size)
    }
  }

  def isTestMode(implicit modeDao: ModeDao) = {
    val mode = Utils.execFuture(modeDao.select)
    if (mode.test == "t") true else false
  }

  def createTempDirectory(prefix: String)(implicit modeDao: ModeDao) = {
    if (isTestMode) Tool.testDir else Files.createTempDirectory(prefix).toFile
  }

  def deleteDirectory(direcotry: File)(implicit modeDao: ModeDao) = {
    if (!isTestMode) Utils.deleteDirectory(direcotry)
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Tool.userDir, userId.toString)
  }

  def getUserIdDir(userId: Int) = {
    new File(Tool.userDir, userId.toString)
  }

  def getContentDisposition(url: String) = {
    val encodeUrl = Tool.urlEncode(url)
    s"attachment; filename*=utf-8''${encodeUrl}"
  }

  def urlEncode(url: String) = {
    URLEncoder.encode(url, "UTF-8")
  }

  def fileMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirOp(fieldName, dir).get
  }

  def fileMoveFile(fieldName: String, destFile: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveFileOp(fieldName, destFile).get
  }

  def fileMoveDirOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    val destFile = new File(dir, tempFile.filename)
    fileMoveFileOp(fieldName, destFile)
  }

  def fileMoveFileOp(fieldName: String, destFile: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    if (tempFile.ref.path.toFile.length() > 0) {
      tempFile.ref.moveTo(destFile, replace = true)
      Some(destFile)
    } else None
  }

}
